import { _decorator, Component, Node, Vec2, Vec3, TiledMap, resources, TiledMapAsset, EventTarget, UITransform, Prefab, instantiate } from 'cc';
import Singleton from '../Base/Singleton';
import EventManager from '../Base/EventManager';
import { MapController } from './MapController';
const { ccclass, property } = _decorator;


@ccclass('MapManager')
export class MapManager extends Singleton {
    static get Instance() {
        return super.GetInstance<MapManager>();
    }

    @property(Prefab)
    mapPrefab: Prefab = null;

    // 地图块尺寸（世界单位）
    @property
    public chunkWidth: number = 1280;
    @property
    public chunkHeight: number = 720;

    // 加载半径（区块数量）
    @property
    public loadRadius: number = 1;

    // 当前加载的地图块
    private loadedChunks: Map<string, TiledMap> = new Map();

    // 玩家节点
    public playerNode: Node = null!;

    // 当前玩家所在区块坐标
    private currentPlayerChunk: Vec2 = new Vec2(0, 0);

    // 正在加载的区块
    private loadingChunks: Set<string> = new Set();

    // 区块加载队列
    private loadQueue: Array<{ x: number, y: number }> = [];

    // 最大同时加载数量
    @property
    private maxConcurrentLoads: number = 2;

    // 当前加载数量
    private currentLoads: number = 0;

    async init(playerNode: Node) {
        console.log("MapManager init");
        await this.updateMap(0, 0);
        await this.processLoadQueue();
        console.log("MapManager 初始化完成 - >>", this.loadedChunks.get(this.getChunkKey(0, 0)).name);
        this.playerNode = playerNode;
        EventManager.Instance.emit("PLAYER_CHUNK_CHANGED", {
            tileMap: this.loadedChunks.get(this.getChunkKey(0, 0)),
            pos: new Vec2(0, 0)
        });


    }

    protected update(dt: number): void {
        if (!this.playerNode) return;
        // console.log("MapManager update");
        // 更新地图块
        this.updateChunks();

        // 处理加载队列
        this.processLoadQueue();
    }

    /**
     * 更新需要加载的区块
     */
    private updateChunks(): void {
        // 获取玩家世界坐标
        const playerPos = this.node.getComponent(UITransform).convertToWorldSpaceAR(this.playerNode.getPosition(), this.playerNode.getPosition());

        // 计算玩家所在区块坐标
        const playerChunkX = Math.floor(playerPos.x / this.chunkWidth);
        const playerChunkY = Math.floor(playerPos.y / this.chunkHeight);

        // 检查区块是否变化
        if (playerChunkX !== this.currentPlayerChunk.x || playerChunkY !== this.currentPlayerChunk.y) {
            this.currentPlayerChunk.set(playerChunkX, playerChunkY);

            console.log(`玩家进入区块: ${playerChunkX}, ${playerChunkY}`);

            this.updateMap(playerChunkX, playerChunkY);

            console.log(this.loadedChunks.get(this.getChunkKey(playerChunkX, playerChunkY)));
            EventManager.Instance.emit("PLAYER_CHUNK_CHANGED", {
                tileMap: this.loadedChunks.get(this.getChunkKey(playerChunkX, playerChunkY)),
                pos: new Vec2(playerChunkX, playerChunkY)
            });
        }
    }

    async updateMap(playerChunkX: number, playerChunkY: number): Promise<void> {

        // 需要加载的新区块
        const chunksToLoad = new Set<string>();

        // 计算加载范围 
        for (let dx = -this.loadRadius; dx <= this.loadRadius; dx++) {
            for (let dy = -this.loadRadius; dy <= this.loadRadius; dy++) {
                const x = playerChunkX + dx;
                const y = playerChunkY + dy;
                const key = this.getChunkKey(x, y);
                chunksToLoad.add(key);

                // 添加到加载队列（如果需要）
                if (!this.loadedChunks.has(key) && !this.loadingChunks.has(key)) {
                    // console.log(`添加到加载队列: ${key}`);
                    this.loadQueue.push({ x, y });
                }
            }
        }

        // 卸载超出范围的区块
        this.unloadOutdatedChunks(chunksToLoad);
    }

    /**
     * 处理加载队列
     */
    private async processLoadQueue(): Promise<void> {
        if (this.currentLoads >= this.maxConcurrentLoads || this.loadQueue.length === 0) {
            return;
        }
        while (this.loadQueue.length > 0 && this.currentLoads < this.maxConcurrentLoads) {
            const { x, y } = this.loadQueue.shift()!;
            await this.loadChunk(x, y);
        }

    }

    /**
     * 加载单个地图块
     */
    private async loadChunk(chunkX: number, chunkY: number): Promise<void> {
        const key = this.getChunkKey(chunkX, chunkY);

        // 检查是否已加载或正在加载
        if (this.loadedChunks.has(key) || this.loadingChunks.has(key)) {
            console.log(`区块 ${key} 已加载或正在加载`);
            return;
        }

        this.loadingChunks.add(key);
        this.currentLoads++;

        const tmxPath = `MapTile/map_${chunkX}_${chunkY}`;
        // console.log(`开始加载地图块: ${tmxPath}`);

        return new Promise<void>((resolve) => {
            resources.load(tmxPath, TiledMapAsset, (err, asset) => {
                this.currentLoads--;
                this.loadingChunks.delete(key);

                if (err) {
                    // console.warn(`加载地图块失败: ${tmxPath}`, err);
                    resolve();
                    return;
                }

                try {
                    // 创建地图节点
                    const tiledMapNode = instantiate(this.mapPrefab);
                    tiledMapNode.name = `Chunk_${key}`
                    let tiledMap = tiledMapNode.getComponent(TiledMap);
                    if (!tiledMap) {
                        tiledMap = tiledMapNode.addComponent(TiledMap);
                    }
                    tiledMap.node.layer = 1;

                    // 安全设置地图资源
                    if (asset) {
                        tiledMap.tmxAsset = asset;
                        let mapController = tiledMapNode.getComponent(MapController);
                        if (!mapController) {
                            mapController = tiledMapNode.addComponent(MapController);
                        }
                    } else {
                        console.error(`地图资源为空: ${tmxPath}`);
                        resolve();
                        return;
                    }

                    // 设置区块位置
                    const worldPos = new Vec3(
                        chunkX * this.chunkWidth,
                        chunkY * this.chunkHeight,
                        0
                    );
                    tiledMapNode.setPosition(worldPos);

                    tiledMapNode.setParent(this.node);
                    this.loadedChunks.set(key, tiledMap);
                    console.warn(`加载地图块成功: ${key}`);

                    // 发送区块加载事件
                    EventManager.Instance.emit("CHUNK_LOADED", {
                        chunkX,
                        chunkY,
                        worldPos
                    });

                } catch (error) {
                    console.error(`处理地图块时出错: ${tmxPath}`, error);
                }

                resolve();
            });
        });
    }

    /**
     * 卸载多余区块
     */
    private unloadOutdatedChunks(validKeys: Set<string>): void {
        this.loadedChunks.forEach((tiledMap, key) => {
            if (!validKeys.has(key)) {
                const [chunkX, chunkY] = this.parseChunkKey(key);
                const worldPos = tiledMap.node.position;

                try {
                    // 移除节点
                    tiledMap.node.destroy();

                    // 释放资源
                    const tmxPath = `MapTile/map_${chunkX}_${chunkY}`;
                    resources.release(tmxPath);

                    this.loadedChunks.delete(key);

                    // 发送区块卸载事件
                    EventManager.Instance.emit("CHUNK_UNLOADED", {
                        chunkX,
                        chunkY,
                        worldPos
                    })

                } catch (error) {
                    console.error(`卸载地图块时出错: ${key}`, error);
                }
            }
        });
    }

    /**
     * 生成区块key
     */
    private getChunkKey(x: number, y: number): string {
        return `${x},${y}`;
    }

    /**
     * 解析区块key
     */
    private parseChunkKey(key: string): [number, number] {
        const [x, y] = key.split(',').map(Number);
        return [x, y];
    }

    /**
     * 获取玩家当前所在区块坐标
     */
    public getCurrentPlayerChunk(): Vec2 {
        return this.currentPlayerChunk.clone();
    }

    /**
     * 获取指定区块的世界坐标范围
     */
    public getChunkWorldBounds(chunkX: number, chunkY: number): { min: Vec3, max: Vec3 } {
        return {
            min: new Vec3(
                chunkX * this.chunkWidth,
                chunkY * this.chunkHeight,
                0
            ),
            max: new Vec3(
                (chunkX + 1) * this.chunkWidth,
                (chunkY + 1) * this.chunkHeight,
                0
            )
        };
    }
}